package intermouse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Szórádi Balázs
 * @version 1.0
 * @since 2013-03-24
 */
public class Field {

	/**
	 * A mezőn lévő FieldObject-ek tárolója
	 */
	private List<FieldObject> obj;

	/**
	 * A mezőn lévő szagok tárolója
	 */
	private List<Smell> smells;

	/**
	 * Referenciák a mezővel szomszédos mezőkre
	 */
	private List<Field> adjacentFields;

	private int coordsx, coordsy;

	private boolean isDirty;
	
	private FieldTypes fieldType;
	
	private DrawableField drawableField;
	
	/**
	 * Konstruktor
	 */
	public Field() {
		obj = new ArrayList<FieldObject>();
		smells = new ArrayList<Smell>();
		adjacentFields = new ArrayList<Field>();
		drawableField = new DrawableField(coordsx, coordsy);
		isDirty = true;
	}

	/**
	 * Beállítja az mezőt újraralzolásra.
	 * 
	 * @return void
	 */
	public void setDirty()
	{
		isDirty = true;
	}
	
	/**
	 * @return A FieldObjectek listáját adja vissza.
	 */
	public List<FieldObject> getObj() {
		return new ArrayList<FieldObject>(obj);
	}

	public void setCoords(int x, int y) {
		coordsx = x;
		coordsy = y;
		this.drawableField.setCoords(x, y);
	}

	/**
	 * Szomszédos mezők listájának lekérdezése.
	 * 
	 * @return Szomszédos mezők listája.
	 */
	public List<Field> getAdjacentFields() {
		Logger.printToConsole(">> Field.getAdjacentFields() : List<Field>");
		Logger.printToConsole("<< return");
		// List<Field> ret = new ArrayList();
		// for(int i = 0; i < adjacentFields.size(); i++)
		// ret.add(adjacentFields.get(i));
		// return ret;
		return adjacentFields;
	}

	/**
	 * Mezőn lévő szagok listájának lekérdezése.
	 * 
	 * @return Mezőn lévő szagok listája.
	 */
	public List<Smell> getSmells() {
		Logger.printToConsole(">> Field.getSmells() : List<Smell>");
		Logger.printToConsole("<< return");
		return smells;
	}

	/**
	 * Eltünteti a mezőn lévő hangyaszagot, úgy, hogy meghívja a smells lista
	 * minden elemére a deodorantReaction() függvényt, ha hamissal tér vissza,
	 * akkor nem töröljük, ha igazzal akkor igen, mert az hangyaszag.
	 * 
	 * @param radius
	 *            A radius paraméterrel megadjuk, hogy milyen távolságban hívjuk
	 *            meg a környező mezőkre is ezt a függvényt.
	 * @return boolean: sikerült-e hangyaszagot törölni
	 */
	public boolean applyAntDeodorant(int radius) {
		Logger.printToConsole(">> Field.applyAntDeodorant() : void");
		boolean ret = false;
		
		Iterator<Smell> it = smells.iterator();
		while (it.hasNext()) {
			Smell fo = it.next();
			if (fo.deodorantReaction())
			{
				TestCommandParser.log("AntSmell vanishes at " + this.toString() + ".");
				it.remove();
				ret = true;
			}
		}
		
		GraphicsManager.getInstance().updateWidget();
		
		this.setDirty();
		
		TestCommandParser.log("Deodorant used at " + this.toString() + ".");
		Logger.printToConsole("<< return");
		return ret;
	}

	/**
	 * Ha valami támadást akar indítani ez ellen a mező ellen (illetve a rajta
	 * lévő objektumok ellen), akkor ezt a függvényt hívja meg, ami továbbhív: a
	 * rajta lévő objektumok attack() függvényét hívja meg.
	 * 
	 * @return Visszatérési értéke boolean. Akkor igaz, ha egy hangya meghalt a
	 *         támadás során (valamelyik FieldObject igazzal tért vissza).
	 */
	public boolean attack() {
		Logger.printToConsole(">> Field.attack() : boolean");
		boolean ret = false;
		for (FieldObject i : obj) {
			if (i.attack())
				ret = true;
		}
		Logger.printToConsole("<< return");
		return ret;
	}

	/**
	 * Meghívja a rajta lévő objektumok beginRound() metódusát.
	 * 
	 * @return Void visszatérési érték.
	 */
	public void beginRound() {
		Logger.printToConsole(">> Field.beginRound() : void");
		Iterator<FieldObject> it = obj.iterator();
		while (it.hasNext()) {
			FieldObject fo = it.next();
			if (fo.getDead())
			{
				it.remove();
				this.setDirty();
			}
		}
		Iterator<Smell> is = smells.iterator();
		while (is.hasNext()) {
			Smell sm = is.next();
			sm.beginRound();
			if(sm.getStrength()<=0) 
			{
				is.remove();
				// nem jó: smells.remove(is);
				this.setDirty();
			}
		}
		
		if (isDirty)
		{
			isDirty = false;
			drawableField.redraw(obj, smells);
		}
		
		Logger.printToConsole("<< return");
	}

	/**
	 * Megadja, hogy a referenciaként kapott hangya ráléphet-e az adott mezőre,
	 * ehhez meghívja az obj listában tárolt FieldObject objektumok canStep(Ant
	 * ant) függvényeit.
	 * 
	 * @return Boolean érték, amely igaz, ha a hangya az adott mezőre léphet.
	 */
	public boolean canStep(Ant ant) {
		boolean ret = true;
		Logger.printToConsole(">> Field.canStep(Ant) : boolean");
		for (FieldObject i : obj) {
			if (!i.getDead()) {
				try {
					if (!i.canStep(ant)) {
						ret = false;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		Logger.printToConsole("<< return");
		return ret;
	}

	public void deleteFieldObject(FieldObject f) {
		try {
			obj.remove(f);
		} catch (NullPointerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Megadja, hogy a referenciaként kapott hangyászsün ráléphet-e az adott
	 * mezőre, ehhez meghívja az obj listában tárolt FieldObject objektumok
	 * canStep(AntEater antEater, int direction) függvényeit.
	 * 
	 * @return Boolean érték, amely igaz, ha a hangyászsün az adott mezőre
	 *         léphet.
	 */
	public boolean canStep(AntEater anteater, int direction) {
		boolean ret = true;
		Logger.printToConsole(">> Field.canStep(AntEater, int) : boolean");
		
		/*for (FieldObject i : obj) {
			if (!i.canStep(anteater, direction))
				ret = false;
		}*/
		Iterator<FieldObject> it = obj.iterator();
		while(it.hasNext())
		{
			FieldObject o = it.next();
			if (!o.canStep(anteater, direction))
				ret = false;
		}
		
		Logger.printToConsole("<< return");
		return ret;
	}

	/**
	 * Megadja, hogy a referenciaként kapott kő ráléphet-e az adott mezőre,
	 * ehhez meghívja az obj listában tárolt FieldObject objektumok
	 * canStep(Stone stone, boolean isFirst, int direction) függvényeit.
	 * 
	 * @return Boolean érték, amely igaz, ha a kő az adott mezőre léphet.
	 */
	public boolean canStep(Stone stone, boolean isFirst, int direction) {
		boolean ret = true;
		Logger.printToConsole(">> Field.canStep(Stone, boolean, int) : boolean");
		
		/*
		for (FieldObject i : obj) {
			if (!i.canStep(stone, isFirst, direction))
				ret = false;
		} Régi iterálás*/
		
		Iterator<FieldObject> it = obj.iterator();
		while(it.hasNext())
		{
			FieldObject o = it.next();
			if (!o.canStep(stone, isFirst, direction))
				ret = false;
		}
		
		Logger.printToConsole("<< return");
		return ret;
	}

	/**
	 * Visszaadja, hogy a mezőn mennyi étel található, ehhez az obj lista minden
	 * elemére meghívja az isFood() függvényt és megszámolja, hány true értéket
	 * kapott vissza.
	 * 
	 * @return Visszatér egy int értékkel, mely a mezőn lévő ételek számával
	 *         egyenlő.
	 */
	public int getFoodCount() {
		Logger.printToConsole(">> Field.getFoodCount() : int");
		int cnt = 0;
		for (FieldObject i : obj) {
			if (!i.getDead())
				if (i.isFood())
					cnt++;
		}
		return cnt;
	}

	/**
	 * A mezőn lévő halott ételek eltakarítása.
	 * 
	 * @return Void értékkel tér vissza.
	 */
	public void deleteDeadFood() {
		Logger.printToConsole(">> Field.deleteDeadFood() : void");

		Iterator<FieldObject> it = obj.iterator();
		while (it.hasNext()) {
			FieldObject fo = it.next();
			if (fo.isFood()) {
				if (fo.getDead()) {
					// ez lehet hogy nem fog működni mert azt töröljük épp amin
					// iterálunk
					it.remove();
				}
			}
		}

		Logger.printToConsole("<< return");
	}

	/**
	 * Felvesz egy új elemet (szagot) a smells listába.
	 * 
	 * @param smell
	 *            A hozzáadandó új szag.
	 * @return Void visszatérési érték.
	 */
	public void addSmell(Smell smell) {
		Logger.printToConsole(">> Field.addSmell(Smell) : void");
		smells.add(smell);
		Logger.printToConsole("<< return");
	}

	/**
	 * Felvesz egy új elemet (FieldObject) az obj listába.
	 * 
	 * @param o
	 *            A hozzáadandó új FieldObject.
	 * @return Void visszatérési érték.
	 */
	public void addFieldObject(FieldObject o) {
		Logger.printToConsole(">> Field.addFieldObject() : void");
		obj.add(o);
		Logger.printToConsole("<< return");
		setDirty();
	}

	public String toString() {
		return coordsx + "," + coordsy;
	}
}
